import 'dart:async';
import 'dart:convert';
import 'dart:io';

import 'package:cross_file/cross_file.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:http/http.dart' as http;
import 'package:http_parser/http_parser.dart';
import 'package:ichinesereader/constants.dart';
import 'package:ichinesereader/controller/cache.dart';
import 'package:record/record.dart';

import 'BGSinglePlayer.dart';
import 'SampleAudioPlayer.dart';

class BGExamRecorder extends StatefulWidget {
  BGExamRecorder(
      {Key? key,
      this.fileId,
      this.isRecognize = false,
      this.isRecordSmall = false,
      this.questionId,
      this.number,
      this.getKeywords,
      this.isTest = false,
      this.actionNum = 0,
      required this.getFileId})
      : super(key: key);

  final String? fileId;
  final bool isRecognize;
  final bool isRecordSmall;
  final bool isTest;
  final int actionNum;
  final String? questionId;
  final int? number;
  final Function getFileId;
  final Function? getKeywords;

  @override
  State<BGExamRecorder> createState() => _BGExamRecorderState();
}

class _BGExamRecorderState extends State<BGExamRecorder> with SingleTickerProviderStateMixin {
  final _audioRecorder = Record();
  RxString _localPath = ''.obs;
  RxString _fileId = ''.obs;
  RxBool _isRecording = false.obs;
  RxInt _recordDuration = 0.obs;
  RxBool _isShowPlayer = false.obs;
  Timer? _timer;

  @override
  Widget build(BuildContext context) {
    setDefaultStatus();
    if (widget.fileId != '') {
      _fileId.value = widget.fileId!;
      _stopRecordState();
    }
    if (widget.actionNum == 1) {
      _start();
    } else if (widget.actionNum == 2) {
      _stop();
    }
    return Container(
        padding: const EdgeInsets.all(15),
        width: MediaQuery.of(Get.context!).size.width,
        height: widget.isRecordSmall ? 90 : 200,
        decoration: BoxDecoration(
            color: Color.fromARGB(209, 236, 241, 241),
            borderRadius: BorderRadius.all(
              Radius.circular(10),
            )),
        child: Container(
            child: widget.isRecordSmall
                ? Row(children: [
                    SizedBox(width: 10),
                    Obx(() {
                      return _buildRecordStopControl(_isRecording.value, _isShowPlayer.value);
                    }),
                    SizedBox(width: 40),
                    Obx(() {
                      return _buildTimer(_recordDuration.value.toInt(), _isRecording.value);
                    }),
                    Obx(() {
                      return _buildPlayerWidget(_localPath.value, _fileId.value);
                    })
                  ])
                : Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Row(mainAxisAlignment: MainAxisAlignment.center, children: [
                        SizedBox(width: 130),
                        Obx(() {
                          return _buildRecordStopControl(_isRecording.value, _isShowPlayer.value);
                        }),
                        SizedBox(width: 50),
                        Obx(() {
                          return _buildTimer(_recordDuration.value.toInt(), _isRecording.value);
                        })
                      ]),
                      SizedBox(height: 20),
                      Obx(() {
                        return _buildPlayerWidget(_localPath.value, _fileId.value);
                      })
                    ],
                  )));
  }

  ///     ************* Widgets  *************
  Widget _buildRecordStopControl(isRecording, isShowPlayer) {
    late Icon icon;
    late Color color;
    if (isRecording == true) {
      icon = const Icon(Icons.stop, color: Colors.red, size: 30);
      color = Colors.red.withOpacity(0.1);
    } else {
      icon = Icon((isShowPlayer && !widget.isTest) ? Icons.replay_sharp : Icons.mic, color: Color.fromARGB(255, 98, 191, 240), size: 30);
      color = Color.fromARGB(255, 98, 191, 240).withOpacity(0.1);
    }

    return ClipOval(
      child: Material(
        color: color,
        child: InkWell(
          child: SizedBox(width: 56, height: 56, child: icon),
          onTap: () {
            if (!widget.isTest) {
              isRecording == true ? _stop() : _start();
            }
          },
        ),
      ),
    );
  }

  Widget _buildTimer(recordDuration, bool isShowTime) {
    if (!isShowTime || widget.isTest) {
      return widget.isRecordSmall ? SizedBox() : SizedBox(width: 80);
    }
    final String minutes = _formatNumber(recordDuration ~/ 60);
    final String seconds = _formatNumber(recordDuration % 60);
    return ClipOval(
      child: Material(
        child: Container(
          height: 40,
          width: 80,
          alignment: Alignment.center,
          child: Text(
            '$minutes : $seconds',
            style: const TextStyle(
              color: Colors.red,
            ),
          ),
        ),
      ),
    );
  }

  String _formatNumber(int number) {
    String numberStr = number.toString();
    if (number < 10) {
      numberStr = '0' + numberStr;
    }
    return numberStr;
  }

  Widget _buildPlayerWidget(String audioUrl, String? audioId) {
    if (_isShowPlayer.value == true && !widget.isTest) {
      if (widget.isRecordSmall) {
        if (_isRecording.value) {
          return SizedBox();
        } else {
          return Container(
              padding: const EdgeInsets.all(1),
              decoration: BoxDecoration(
                color: Color.fromARGB(50, 167, 169, 170),
                borderRadius: BorderRadius.all(Radius.circular(10)),
              ),
              child: SampleAudioPlayer(name: 'audioPlayerExam', audioUrl: audioUrl, audioId: audioId));
        }
      } else {
        return Container(
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(
              color: Color.fromARGB(50, 167, 169, 170),
              borderRadius: BorderRadius.all(Radius.circular(10)),
            ),
            child: SampleAudioPlayer(name: 'audioPlayerExam', audioUrl: audioUrl, audioId: audioId));
      }
    } else {
      return SizedBox();
    }
  }

  ///     ************* Recorder Actions  *************
  Future<void> _start() async {
    try {
      BGSinglePlayer().stop();
      if (await _audioRecorder.hasPermission()) {
        await _audioRecorder.start(samplingRate: 16000, bitRate: 24000, numChannels: 1);
        await _audioRecorder.isRecording();
        _isRecording.value = true;
        _setRecordTime();
      }
    } catch (e) {
      if (kDebugMode) {
        print(e);
      }
    }
  }

  Future<void> _stop() async {
    final path = await _audioRecorder.stop();
    _localPath.value = path!;
    _stopRecordState();
    _save();
  }

  void _stopRecordState() {
    _timer?.cancel();
    _isRecording.value = false;
    _recordDuration.value = 0;
    if (_fileId.value != '') _isShowPlayer.value = true;
  }

  void _setRecordTime() {
    _timer?.cancel();
    _timer = Timer.periodic(const Duration(seconds: 1), (Timer t) {
      _recordDuration.value++;
    });
  }

  ///     ************* Widgets Actions  *************
  Future<void> _save() async {
    String fileId = '';
    if (widget.isRecognize) {
      Map? result = await _recognizeRecordFile(widget.questionId, widget.number);
      if (result != null) {
        fileId = result['fileId'];
        List keywordsList = result['sameChars'];
        int score = result['score'];
        if (widget.getKeywords != null) {
          widget.getKeywords!(keywordsList, score);
        }
        _isShowPlayer.value = true;
      }
    } else {
      fileId = await _saveRecordFile();
      _isShowPlayer.value = true;
    }

    if (fileId.isEmpty) {
      Get.snackbar('Message'.tr, 'Error to save'.tr, snackPosition: SnackPosition.TOP);
    } else {
      widget.getFileId(fileId);
    }
  }

  Future<String> _saveRecordFile() async {
    EasyLoading.show();
    final box = Hive.box('appconfig');
    var _authtoken = box.get(CacheManagerKey['authtoken'].toString());
    var uri = Uri.parse('${Constants.BaseAPI}studentmanager/file');
    var request = http.MultipartRequest('POST', uri);
    request.headers.addAll({'authtoken': _authtoken});
    try {
      late var bytes;
      if (_localPath.value.startsWith('blob:http')) {
        bytes = await XFile(_localPath.value).readAsBytes();
      } else {
        bytes = await File.fromUri(Uri.parse(_localPath.value)).readAsBytes();
      }
      request.files.add(http.MultipartFile.fromBytes('file', bytes, filename: 'file', contentType: MediaType('audio', 'mpeg')));
      var response = await request.send();
      final respStr = await response.stream.bytesToString();
      var fileId = jsonDecode(respStr)['fileId'];
      if (fileId != null) {
        return fileId;
      }
    } catch (error) {
      print(error);
    } finally {
      EasyLoading.dismiss();
    }
    return '';
  }

  Future<Map?> _recognizeRecordFile(String? questionId, int? number) async {
    EasyLoading.show();
    final box = Hive.box('appconfig');
    var _authtoken = box.get(CacheManagerKey['authtoken'].toString());
    var uri = Uri.parse('${Constants.BaseAPISuper}superadmin/speech/recognition/$questionId/$number');
    var request = http.MultipartRequest('POST', uri);
    request.headers.addAll({'authtoken': _authtoken});
    try {
      late var bytes;
      if (_localPath.value.startsWith('blob:http')) {
        bytes = await XFile(_localPath.value).readAsBytes();
      } else {
        bytes = await File.fromUri(Uri.parse(_localPath.value)).readAsBytes();
      }
      request.files.add(http.MultipartFile.fromBytes('file', bytes, filename: 'file.m4a', contentType: MediaType('audio', 'mpeg')));
      var response = await request.send();
      final respStr = await response.stream.bytesToString();
      var result = jsonDecode(respStr);
      if (result != null && result['status'] == 1000) {
        return result['result'];
      }
    } catch (error) {
      print(error);
    } finally {
      EasyLoading.dismiss();
    }
    return null;
  }

  void setDefaultStatus() {
    _localPath.value = '';
    _isRecording.value = false;
    _recordDuration.value = 0;
    _isShowPlayer.value = false;
    _timer?.cancel();
  }

  @override
  void dispose() {
    _audioRecorder.dispose();
    super.dispose();
  }
}
